#include "ProductIO.h"

/* Prototype function */
void printRecord(ostream &output, Stock stock);

/* Constructor for Product IO */
ProductIO::ProductIO(string path)
{
	filePath = path;

	/* Initialize a File Reader */
	inputFileStream.open(filePath, ios::in);
	if(!inputFileStream) 
		displayErrorMessage("Error Message: Fail to open file\n");

	/* Initialize a File Writer */
	outputFileStream.open("Product2.txt", ios::out | ios::trunc);
	if(!outputFileStream) 
		displayErrorMessage("Error Message: Fail to open file\n");
}

/* Destructor for Product IO */
ProductIO::~ProductIO()
{
	filePath.clear();
	inputFileStream.close();
	outputFileStream.close();
}

/* Load data and Create Object into Vector List */
void ProductIO::loadDataFromFile(vector< Product *> &productList)
{
	string data;
	int itemIndex = 0;
	int entryIndex = 0;
	
	while(getline(inputFileStream, data)) // read data from txt line by line
	{
		vector<string> attr;  // data for each entry, used to construct object attributes
		if(data.find(';') == string::npos) { // ignore the line which does not have ';'
			getline(inputFileStream, data);
			itemIndex++;
			entryIndex = 0;
			continue;
		}

		// spliting the data 
		char *cstr = new char[data.length()+1];
		strcpy(cstr, data.c_str());  // convert string to cstring
		char *p = std::strtok(cstr,";"); // split by ";"
		
		int attrIndex = 0;
		
		while(p != 0)
		{
			if(attrIndex != 0) // remove the preceding ' ' for later elements.
				*p++;
			string s = p; // convert back to string
			attr.push_back(s);
			attrIndex++;
			p = strtok(NULL, ";");	
		}
		entryIndex++;

		delete[] cstr;

		// new a object here.

		bool portable;

		switch(itemIndex - 1)
		{
		case 0:
			productList.push_back(new USB(attr[0], attr[1], attr[2], attr[3], atoi(attr[4].c_str()), atoi(attr[5].c_str())));
			break;
		case 1:
			// create HD(attr[0],attr[1],...)
			portable = ((attr[2] == "Yes")? true : false);
			productList.push_back(new HardDisk(attr[0], attr[1], portable, attr[3], atoi(attr[4].c_str()), atoi(attr[5].c_str())));
			break;
		case 2:
			// create Monitor(attr[0],attr[1],...)
			productList.push_back(new Monitor(attr[0], atoi(attr[1].c_str()), attr[2], atoi(attr[3].c_str()), atoi(attr[4].c_str())));
			break;
		case 3:
			// create SD(attr[0],attr[1],...)
			productList.push_back(new SDCard(attr[0], attr[1], attr[2], attr[3], atoi(attr[4].c_str()), atoi(attr[5].c_str())));
			break;
		case 4:
			// create App(attr[0],attr[1],...)
			productList.push_back(new Software(attr[0], attr[1], attr[2], attr[3], attr[4], atoi(attr[5].c_str()), atoi(attr[6].c_str())));
			break;
		default:
			cerr << "Error Message: Item Index is invalid\n";
		}
	}
}

/* Print All Items in the Console */
void ProductIO::viewRecord(const Stock &stock)
{
	printRecord(cout, stock);
}

/* Write All Items to Text File (e.g. Product.txt) */
void ProductIO::commitChanges(const Stock &stock)
{
	// output the changes to "Product.txt"
	printRecord(outputFileStream, stock);
	cout << "The changes are committed.\n";
}

/* Display Error Message */
void ProductIO::displayErrorMessage(string errorMsg)
{
	cerr << errorMsg << endl;
	exit(1);
}

/* Format the output of All Items */
void printRecord(ostream &output, Stock stock)
{
	map <int, string> header, detail;

	for(int i = 0; i < 5; i++)
	{
		output << stock.getProductName(i) << ":" << endl;
		stock.setBufferItem(i, 0);
		header = stock.getItemsHeader();
		detail = stock.getItemsDetails();
		for (int j = 0; j < header.size(); j++ )
			output << "[" << header[j] << "] ";
		output << endl;
		for (int j = 0; j < detail.size()/header.size(); j++ )
		{
			for (int k = 0; k < header.size(); k++)
			{
				output << detail[j*header.size()+k];
				if (k != header.size() - 1)
					output << "; ";
			}
			output << endl;
		}
	}
}

